package com.et114.components.acegi.intercept.method;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.ConfigAttributeEditor;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.intercept.method.MethodDefinitionSource;

import org.springframework.util.Assert;

import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.CodeSignature;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.et114.components.acegi.cache.AcegiCacheManager;
import com.et114.components.acegi.resourcedetails.ResourceDetails;

/**
 * 在resourceCache中保存每个方法对应的ResourceDetails
 * @author guanhw
 */
public class DBMethodDefinitionSource implements MethodDefinitionSource {
	private static final Log	logger	= LogFactory.getLog( DBMethodDefinitionSource.class );
	private AcegiCacheManager	acegiCacheManager;
	public void setAcegiCacheManager ( AcegiCacheManager acegiCacheManager ) {
		this.acegiCacheManager = acegiCacheManager;
	}

	// ~ Methods
	// ========================================================================================================

	public ConfigAttributeDefinition getAttributes ( Object object )  {
		Assert.notNull( object, "Object cannot be null" );

		if ( object instanceof MethodInvocation ) {
			MethodInvocation miv = ( MethodInvocation ) object;
			try {
				return this.lookupAttributes( miv.getThis().getClass(), miv.getMethod() );
			} catch ( Exception e ) {
				logger.error( e.getMessage(), e );
			}

		}

		if ( object instanceof JoinPoint ) {
			JoinPoint jp = ( JoinPoint ) object;
			Class targetClazz = jp.getTarget().getClass();
			String targetMethodName = jp.getStaticPart().getSignature()
					.getName();
			Class [ ] types = ( ( CodeSignature ) jp.getStaticPart()
					.getSignature() ).getParameterTypes();

			if ( logger.isDebugEnabled() ) {
				logger.debug( "Target Class: " + targetClazz );
				logger.debug( "Target Method Name: " + targetMethodName );

				for ( int i = 0; i < types.length; i++ ) {
					logger.debug( "Target Method Arg #" + i + ": "
									+ types [ i ] );
				}
			}

			try {
				return this.lookupAttributes( targetClazz, targetClazz
						.getMethod( targetMethodName, types ) );
			} catch ( Exception nsme ) {
				logger.error( nsme.getMessage(), nsme );
			}
		}

		throw new IllegalArgumentException(
				"Object must be a MethodInvocation or JoinPoint" );
	}

	public boolean supports ( Class clazz ) {
		return ( MethodInvocation.class.isAssignableFrom( clazz ) || JoinPoint.class
				.isAssignableFrom( clazz ) );
	}

	/**
	 * 从resourceCache中获取当前方法对应的ResourceDetails{@link ResourceDetails} 最后返回由Role
	 * Name 组装成的ConfigAttributeDefinition(@link ConfigAttributeDefinition)
	 * 
	 * @see org.acegisecurity.intercept.method.AbstractMethodDefinitionSource#lookupAttributes(java.lang.reflect.Method)
	 */
	protected ConfigAttributeDefinition lookupAttributes ( Class clszz , Method mi ) throws Exception {
		Assert.notNull( mi , "lookupAttrubutes in the DBMethodDefinitionSource is null" );
		try {
			//acegiCacheManager.initResourceCache();
			// 获取所有的function
			List methodStrings = acegiCacheManager.getMethods();
			Set auths = new HashSet();
			// 取权限的合集
			for ( Iterator iter = methodStrings.iterator(); iter.hasNext(); ) {
				String methodString = ( String ) iter.next();
				if ( isMatch( clszz, mi, methodString ) ) {
					ResourceDetails resourceDetails = acegiCacheManager.getAuthorityFromCache( methodString );
					if ( resourceDetails == null ) {
						break;
					}
					GrantedAuthority [ ] authorities = resourceDetails.getAuthorities();
					if ( authorities == null || authorities.length == 0 ) {
						break;
					}
					auths.addAll( Arrays.asList( authorities ) );
				}
			}

			if ( auths.size() == 0 ) return null;
			ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();
			String authoritiesStr = " ";

			for ( Iterator iter = auths.iterator(); iter.hasNext(); ) {
				GrantedAuthority authority = ( GrantedAuthority ) iter.next();
				authoritiesStr += authority.getAuthority() + ",";
			}

			String authStr = authoritiesStr.substring( 0, authoritiesStr	.length() - 1 );
			configAttrEditor.setAsText( authStr );
			return ( ConfigAttributeDefinition ) configAttrEditor.getValue();

		} catch ( Exception e ) {
			logger.error( e.getMessage(), e );
			throw new Exception( e.getMessage ( ) ) ;
		}

	}

	public Iterator getConfigAttributeDefinitions ( ) {
		return null;
	}

	/**
	 * Return if the given method name matches the mapped name. The default
	 * implementation checks for "xxx" and "xxx" matches.
	 */
	public static boolean isMatch ( Class clszz , Method mi ,
			String methodString ) {
		boolean isMatch = true;
		try {
			int lastDotIndex = methodString.lastIndexOf( '.' );
			String className = methodString.substring( 0, lastDotIndex );
			String methodName = methodString.substring( lastDotIndex + 1 );

			// 判断类是否相等
			if ( !clszz.getName().equals( className ) )
				isMatch = false;

			// 判断接口是否相等
			Class [ ] interfaces = clszz.getInterfaces();
			for ( int i = 0; i < interfaces.length; i++ ) {
				Class inf = interfaces [ i ];
				if ( inf.getName().equals( className ) ) {
					isMatch = true;
				}
			}

			// 判断方法是否相等
			if ( isMatch
					&& !( mi.getName().equals( methodName )
							|| ( methodName.endsWith( "*" ) && mi.getName()
									.startsWith(
											methodName.substring( 0, methodName
													.length() - 1 ) ) ) || ( methodName
							.startsWith( "*" ) && mi.getName().endsWith(
							methodName.substring( 1, methodName.length() ) ) ) ) )
				isMatch = false;

		} catch ( Exception e ) {
			isMatch = false;
		}
		return isMatch;
	}

}
